package org.design.singleton;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 一个非常简单的单例模式 
 * 1. 私有静态的一个自己 
 * 2. 构造函数私有，这样的话，就不能随意new实例了 
 * 3. 用一个静态方法获得一个实例
 * 4. 针对反射和序列化，我们需要做点额外的事情
 * 
 * @author chenxianpeng
 *
 */
public class SimpleSingleton3 implements Serializable {
	private static SimpleSingleton3 _instance = null;

	private SimpleSingleton3() {
		// TODO Auto-generated constructor stub
		// 防止反射获取多个对象的漏洞 
		// 这种方式只能防止已经执行过getInstance时的代码。
		//因为没有执行getInstance时，_instance永远是null的。
        if (null != _instance) {  
            throw new RuntimeException();  
        }  
	}

	public static SimpleSingleton3 getInstance() {
		if (_instance == null) {
			_instance = new SimpleSingleton3();
		}
		return _instance;
	}
	
	// 防止反序列化获取多个对象的漏洞。  
    // 无论是实现Serializable接口，或是Externalizable接口，当从I/O流中读取对象时，readResolve()方法都会被调用到。  
    // 实际上就是用readResolve()中返回的对象直接替换在反序列化过程中创建的对象。  
    private Object readResolve() throws ObjectStreamException {    
        return _instance;  
    }  

	public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException, IOException {
		//如果在多线程环境下，会发生什么事情
		MyThread t1 = new MyThread();
		MyThread t2 = new MyThread();
		MyThread t3 = new MyThread();
		t1.start();
		t2.start();
		t3.start();
		//我们上面的防反射代码，起了一定的效果，有一定的几率会出现问题
		//我们的暂时可以把防反射的代码去掉
	}

}

class MyThread extends Thread {
	public void run() {
		SimpleSingleton3 ss = SimpleSingleton3.getInstance();
		System.out.println("ss=" + ss);
	}
}
